//! previously compiled dependency
//!
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
+use std::default::Default;
use std::path::PathBuf;
use std::sync::Arc;
}
} else {
let root_package = ws.current()?;
- generate_targets(root_package, profiles, mode, filter, release)?;
+ let all_features = resolve_with_overrides.features(root_package.package_id());
+ generate_targets(root_package, profiles, mode, filter, all_features, release)?;
pkgids.push(root_package.package_id());
};
panic!("`rustc` and `rustdoc` should not accept multiple `-p` flags")
}
(Some(args), _) => {
+ let all_features = resolve_with_overrides.features(to_builds[0].package_id());
let targets = generate_targets(to_builds[0], profiles,
- mode, filter, release)?;
+ mode, filter, all_features, release)?;
if targets.len() == 1 {
let (target, profile) = targets[0];
let mut profile = profile.clone();
}
}
(None, Some(args)) => {
+ let all_features = resolve_with_overrides.features(to_builds[0].package_id());
let targets = generate_targets(to_builds[0], profiles,
- mode, filter, release)?;
+ mode, filter, all_features, release)?;
if targets.len() == 1 {
let (target, profile) = targets[0];
let mut profile = profile.clone();
}
(None, None) => {
for &to_build in to_builds.iter() {
+ let all_features = resolve_with_overrides.features(to_build.package_id());
let targets = generate_targets(to_build, profiles, mode,
- filter, release)?;
+ filter, all_features, release)?;
package_targets.push((to_build, targets));
}
}
profiles: &'a Profiles,
mode: CompileMode,
filter: &CompileFilter,
+ features: Option<&HashSet<String>>,
release: bool)
-> CargoResult<Vec<(&'a Target, &'a Profile)>> {
let build = if release {&profiles.release} else {&profiles.dev};
CompileMode::Doc { .. } => &profiles.doc,
CompileMode::Doctest => &profiles.doctest,
};
- match *filter {
+ let mut targets = match *filter {
CompileFilter::Everything => {
match mode {
CompileMode::Bench => {
- Ok(pkg.targets().iter().filter(|t| t.benched()).map(|t| {
+ pkg.targets().iter().filter(|t| t.benched()).map(|t| {
(t, profile)
- }).collect::<Vec<_>>())
+ }).collect::<Vec<_>>()
}
CompileMode::Test => {
let deps = if release {
base.push((t, deps));
}
}
- Ok(base)
+ base
}
CompileMode::Build | CompileMode::Check => {
- Ok(pkg.targets().iter().filter(|t| {
+ pkg.targets().iter().filter(|t| {
t.is_bin() || t.is_lib()
- }).map(|t| (t, profile)).collect())
+ }).map(|t| (t, profile)).collect()
}
CompileMode::Doc { .. } => {
- Ok(pkg.targets().iter().filter(|t| t.documented())
- .map(|t| (t, profile)).collect())
+ pkg.targets().iter().filter(|t| t.documented())
+ .map(|t| (t, profile)).collect()
}
CompileMode::Doctest => {
if let Some(t) = pkg.targets().iter().find(|t| t.is_lib()) {
}
}
- Ok(Vec::new())
+ Vec::new()
}
}
}
}
};
debug!("found {} `{}`", desc, name);
+
targets.push((t, profile));
}
Ok(())
find(tests, "test", Target::is_test, test)?;
find(benches, "bench", Target::is_bench, &profiles.bench)?;
}
- Ok(targets)
+ targets
+ }
+ };
+
+ //Collect the targets that are libraries or have all required features available.
+ let no_features = HashSet::new();
+ let features = features.unwrap_or(&no_features);
+ let mut compatible_targets = Vec::with_capacity(targets.len());
+ for (target, profile) in targets.drain(0..) {
+ if target.is_lib() || match target.required_features() {
+ Some(f) => !f.iter().any(|f| !features.contains(f)),
+ None => true,
+ } {
+ compatible_targets.push((target, profile));
+ continue;
+ }
+
+ if let CompileFilter::Only { .. } = *filter {
+ let required_features = target.required_features().unwrap();
+ let quoted_required_features: Vec<String> = required_features.iter()
+ .map(|s| format!("`{}`",s))
+ .collect();
+ bail!("target `{}` requires the features: {}\n\
+ Consider enabling them by passing e.g. `--features=\"{}\"`",
+ target.name(),
+ quoted_required_features.join(", "),
+ required_features.join(" "));
}
}
+
+ Ok(compatible_targets)
}
/// Parse all config files to learn about build configuration. Currently
--- /dev/null
+extern crate cargotest;
+extern crate hamcrest;
+
+use cargotest::support::{project, execs};
+use hamcrest::{assert_that, existing_file, not};
+
+#[test]
+fn build_bin_default_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["a"]
+ a = []
+
+ [[bin]]
+ name = "foo"
+ required-features = ["a"]
+ "#)
+ .file("src/main.rs", "fn main() {}");
+
+ assert_that(p.cargo_process("build"),
+ execs().with_status(0));
+ assert_that(&p.bin("foo"), existing_file());
+
+ assert_that(p.cargo_process("build").arg("--no-default-features"),
+ execs().with_status(0));
+ assert_that(&p.bin("foo"), not(existing_file()));
+
+ assert_that(p.cargo_process("build").arg("--bin=foo"),
+ execs().with_status(0));
+ assert_that(&p.bin("foo"), existing_file());
+
+ assert_that(p.cargo_process("build").arg("--bin=foo").arg("--no-default-features"),
+ execs().with_status(101).with_stderr("\
+error: target `foo` requires the features: `a`
+Consider enabling them by passing e.g. `--features=\"a\"`
+"));
+ assert_that(&p.bin("foo"), not(existing_file()));
+}
+
+#[test]
+fn build_bin_arg_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+
+ [[bin]]
+ name = "foo"
+ required-features = ["a"]
+ "#)
+ .file("src/main.rs", "fn main() {}");
+
+ assert_that(p.cargo_process("build").arg("--features").arg("a"),
+ execs().with_status(0));
+ assert_that(&p.bin("foo"), existing_file());
+}
+
+#[test]
+fn build_bin_multiple_required_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["a", "b"]
+ a = []
+ b = ["a"]
+ c = []
+
+ [[bin]]
+ name = "foo_1"
+ path = "src/foo_1.rs"
+ required-features = ["b", "c"]
+
+ [[bin]]
+ name = "foo_2"
+ path = "src/foo_2.rs"
+ required-features = ["a"]
+ "#)
+ .file("src/foo_1.rs", "fn main() {}")
+ .file("src/foo_2.rs", "fn main() {}");
+
+ assert_that(p.cargo_process("build"),
+ execs().with_status(0));
+
+ assert_that(&p.bin("foo_1"), not(existing_file()));
+ assert_that(&p.bin("foo_2"), existing_file());
+
+ assert_that(p.cargo_process("build").arg("--features").arg("c"),
+ execs().with_status(0));
+
+ assert_that(&p.bin("foo_1"), existing_file());
+ assert_that(&p.bin("foo_2"), existing_file());
+
+ assert_that(p.cargo_process("build").arg("--no-default-features"),
+ execs().with_status(0));
+
+ assert_that(&p.bin("foo_1"), not(existing_file()));
+ assert_that(&p.bin("foo_2"), not(existing_file()));
+}
+
+#[test]
+fn build_example_default_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["a"]
+ a = []
+
+ [[example]]
+ name = "foo"
+ required-features = ["a"]
+ "#)
+ .file("examples/foo.rs", "fn main() {}");
+
+ assert_that(p.cargo_process("build").arg("--example=foo"),
+ execs().with_status(0));
+ assert_that(&p.bin("examples/foo"), existing_file());
+
+ assert_that(p.cargo_process("build").arg("--example=foo").arg("--no-default-features"),
+ execs().with_status(101).with_stderr("\
+error: target `foo` requires the features: `a`
+Consider enabling them by passing e.g. `--features=\"a\"`
+"));
+ assert_that(&p.bin("examples/foo"), not(existing_file()));
+}
+
+#[test]
+fn build_example_arg_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+
+ [[example]]
+ name = "foo"
+ required-features = ["a"]
+ "#)
+ .file("examples/foo.rs", "fn main() {}");
+
+ assert_that(p.cargo_process("build").arg("--example=foo").arg("--features").arg("a"),
+ execs().with_status(0));
+ assert_that(&p.bin("examples/foo"), existing_file());
+}
+
+#[test]
+fn build_example_multiple_required_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["a", "b"]
+ a = []
+ b = ["a"]
+ c = []
+
+ [[example]]
+ name = "foo_1"
+ required-features = ["b", "c"]
+
+ [[example]]
+ name = "foo_2"
+ required-features = ["a"]
+ "#)
+ .file("examples/foo_1.rs", "fn main() {}")
+ .file("examples/foo_2.rs", "fn main() {}");
+
+ assert_that(p.cargo_process("build").arg("--example=foo_1"),
+ execs().with_status(101).with_stderr("\
+error: target `foo_1` requires the features: `b`, `c`
+Consider enabling them by passing e.g. `--features=\"b c\"`
+"));
+ assert_that(p.cargo("build").arg("--example=foo_2"),
+ execs().with_status(0));
+
+ assert_that(&p.bin("examples/foo_1"), not(existing_file()));
+ assert_that(&p.bin("examples/foo_2"), existing_file());
+
+ assert_that(p.cargo_process("build").arg("--example=foo_1")
+ .arg("--features").arg("c"),
+ execs().with_status(0));
+ assert_that(p.cargo("build").arg("--example=foo_2")
+ .arg("--features").arg("c"),
+ execs().with_status(0));
+
+ assert_that(&p.bin("examples/foo_1"), existing_file());
+ assert_that(&p.bin("examples/foo_2"), existing_file());
+
+ assert_that(p.cargo_process("build").arg("--example=foo_1")
+ .arg("--no-default-features"),
+ execs().with_status(101).with_stderr("\
+error: target `foo_1` requires the features: `b`, `c`
+Consider enabling them by passing e.g. `--features=\"b c\"`
+"));
+ assert_that(p.cargo("build").arg("--example=foo_2")
+ .arg("--no-default-features"),
+ execs().with_status(101).with_stderr("\
+error: target `foo_2` requires the features: `a`
+Consider enabling them by passing e.g. `--features=\"a\"`
+"));
+
+ assert_that(&p.bin("examples/foo_1"), not(existing_file()));
+ assert_that(&p.bin("examples/foo_2"), not(existing_file()));
+}
+
+#[test]
+fn test_default_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["a"]
+ a = []
+
+ [[test]]
+ name = "foo"
+ required-features = ["a"]
+ "#)
+ .file("tests/foo.rs", "#[test]\nfn test() {}");
+
+ assert_that(p.cargo_process("test"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+"));
+
+ assert_that(p.cargo_process("test").arg("--no-default-features"),
+ execs().with_status(0).with_stderr(format!("\
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"))
+ .with_stdout(""));
+
+ assert_that(p.cargo_process("test").arg("--test=foo"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+"));
+
+ assert_that(p.cargo_process("test").arg("--test=foo").arg("--no-default-features"),
+ execs().with_status(101).with_stderr("\
+error: target `foo` requires the features: `a`
+Consider enabling them by passing e.g. `--features=\"a\"`
+"));
+}
+
+#[test]
+fn test_arg_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+
+ [[test]]
+ name = "foo"
+ required-features = ["a"]
+ "#)
+ .file("tests/foo.rs", "#[test]\nfn test() {}");
+
+ assert_that(p.cargo_process("test").arg("--features").arg("a"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+"));
+}
+
+#[test]
+fn test_multiple_required_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["a", "b"]
+ a = []
+ b = ["a"]
+ c = []
+
+ [[test]]
+ name = "foo_1"
+ required-features = ["b", "c"]
+
+ [[test]]
+ name = "foo_2"
+ required-features = ["a"]
+ "#)
+ .file("tests/foo_1.rs", "#[test]\nfn test() {}")
+ .file("tests/foo_2.rs", "#[test]\nfn test() {}");
+
+ assert_that(p.cargo_process("test"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[/]debug[/]deps[/]foo_2-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+"));
+
+ assert_that(p.cargo_process("test").arg("--features").arg("c"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[/]debug[/]deps[/]foo_1-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]foo_2-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+"));
+
+ assert_that(p.cargo_process("test").arg("--no-default-features"),
+ execs().with_status(0).with_stderr(format!("\
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"))
+ .with_stdout(""));
+}
+
+#[test]
+fn bench_default_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["a"]
+ a = []
+
+ [[bench]]
+ name = "foo"
+ required-features = ["a"]
+ "#)
+ .file("benches/foo.rs", r#"
+ #![feature(test)]
+ extern crate test;
+
+ #[bench]
+ fn bench(_: &mut test::Bencher) {
+ }"#);
+
+ assert_that(p.cargo_process("bench"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] release [optimized] target(s) in [..]
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test bench ... bench: [..] 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+
+"));
+
+ assert_that(p.cargo_process("bench").arg("--no-default-features"),
+ execs().with_status(0).with_stderr(format!("\
+[FINISHED] release [optimized] target(s) in [..]"))
+ .with_stdout(""));
+
+ assert_that(p.cargo_process("bench").arg("--bench=foo"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] release [optimized] target(s) in [..]
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test bench ... bench: [..] 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+
+"));
+
+ assert_that(p.cargo_process("bench").arg("--bench=foo").arg("--no-default-features"),
+ execs().with_status(101).with_stderr("\
+error: target `foo` requires the features: `a`
+Consider enabling them by passing e.g. `--features=\"a\"`
+"));
+}
+
+#[test]
+fn bench_arg_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+
+ [[bench]]
+ name = "foo"
+ required-features = ["a"]
+ "#)
+ .file("benches/foo.rs", r#"
+ #![feature(test)]
+ extern crate test;
+
+ #[bench]
+ fn bench(_: &mut test::Bencher) {
+ }"#);
+
+ assert_that(p.cargo_process("bench").arg("--features").arg("a"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] release [optimized] target(s) in [..]
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test bench ... bench: [..] 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+
+"));
+}
+
+#[test]
+fn bench_multiple_required_features() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["a", "b"]
+ a = []
+ b = ["a"]
+ c = []
+
+ [[bench]]
+ name = "foo_1"
+ required-features = ["b", "c"]
+
+ [[bench]]
+ name = "foo_2"
+ required-features = ["a"]
+ "#)
+ .file("benches/foo_1.rs", r#"
+ #![feature(test)]
+ extern crate test;
+
+ #[bench]
+ fn bench(_: &mut test::Bencher) {
+ }"#)
+ .file("benches/foo_2.rs", r#"
+ #![feature(test)]
+ extern crate test;
+
+ #[bench]
+ fn bench(_: &mut test::Bencher) {
+ }"#);
+
+ assert_that(p.cargo_process("bench"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] release [optimized] target(s) in [..]
+[RUNNING] target[/]release[/]deps[/]foo_2-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test bench ... bench: [..] 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+
+"));
+
+ assert_that(p.cargo_process("bench").arg("--features").arg("c"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] release [optimized] target(s) in [..]
+[RUNNING] target[/]release[/]deps[/]foo_1-[..][EXE]
+[RUNNING] target[/]release[/]deps[/]foo_2-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test bench ... bench: [..] 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+
+
+running 1 test
+test bench ... bench: [..] 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+
+"));
+
+ assert_that(p.cargo_process("bench").arg("--no-default-features"),
+ execs().with_status(0).with_stderr(format!("\
+[FINISHED] release [optimized] target(s) in [..]"))
+ .with_stdout(""));
+}
+